
#ifndef LOD_MATERIAL_H
#define LOD_MATERIAL_H

#include <stdlib.h>
#include <GL/gl.h>

#include "../gl_function_wrappers.h"

//! Material
/*! 
 * \param comptype A type used to represent components of this material.*/
template<class comptype>
class material
{
    public:
    //! Ambient component stored as RGBA
    comptype ambient[4];
    //! Diffuse component stored as RGBA
    comptype diffuse[4];
    //! Specular component stored as RGBA
    comptype specular[4];
    //! Specular exponent of the material (specular degree)
    comptype shininess;

    //! Vertex colour paint
    /*! Specifies whether to use entirely the components of the material, 
     * or to overwrite some of them by the coloures of the vertices */
    bool vcol_paint;

    /*!
     * \param m A material to compare this one with.*/
    bool operator== (const material & m) const
    {
       return (diffuse[0]==m.diffuse[0] &&
               diffuse[1]==m.diffuse[1] &&
               diffuse[2]==m.diffuse[2] &&
               diffuse[3]==m.diffuse[3] &&
               specular[0]==m.specular[0] &&
               specular[1]==m.specular[1] &&
               specular[2]==m.specular[2] &&
               specular[3]==m.specular[3] &&
               ambient[0] == m.ambient[0] &&
               ambient[1] == m.ambient[1] &&
               ambient[2] == m.ambient[2] &&
               ambient[3] == m.ambient[3] &&
               shininess == m.shininess &&
               vcol_paint == m.vcol_paint);
    }

    /*!
     * \param diff A pointer to a diffuse component specified as RGB.
     * \param spec A pointer to a specular component specified as RGB.*/
    material(const comptype* diff, const comptype* spec=NULL, bool vcolpaint=false)
     : vcol_paint(vcolpaint)
    {
        diffuse[0] = diff[0];
        diffuse[1] = diff[1];
        diffuse[2] = diff[2];
        diffuse[3] = 1.0;         // no support for A (in RGBA) component yet 
        
        if(spec!=NULL) {
            specular[0] = spec[0];
            specular[1] = spec[1];
            specular[2] = spec[2];
            specular[3] = 1.0;  // no support for A (in RGBA) component yet 
            init(false,true);//,true);
        }
        else
            init(true,true);//,true);
    }


    material(comptype diffR, comptype diffG, comptype diffB,
            comptype specR, comptype specG, comptype specB,
            bool vcolpaint=false)
     : vcol_paint(vcolpaint)
    {
        diffuse[0] = diffR;
        diffuse[1] = diffG;
        diffuse[2] = diffB;
        diffuse[3] = 1.0;

        specular[0] = specR;
        specular[1] = specG;
        specular[2] = specB;
        specular[3] = 1.0;

        init(false,false);
    }

    material(comptype diffR, comptype diffG, comptype diffB,
            bool vcolpaint=false)
     : vcol_paint(vcolpaint)
    {
        diffuse[0] = diffR;
        diffuse[1] = diffG;
        diffuse[2] = diffB;
        diffuse[3] = 1.0;   // no support for A (in RGBA) component yet 

        init(true,true);
    }

    //! Constructs the default material
    //
    /*! The default material has everything but diffuse component set to default 
     * OpenGL values; it does not use vertex colour paint and it is dull 
     * (shininess is set to 128) */
    material()
     : vcol_paint(false)
    {
        diffuse[3] = 1.0; // in case RGB (not full RGBA) model is used
        init(true,true);
    }


    void set(bool front=true, bool back=true, bool lightsOn=true)
    {
        if(lightsOn)
        {
            if(front & back) {
                GLMATERIALV(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
                GLMATERIALV(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
                GLMATERIALV(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
                GLMATERIAL(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
            }
            else if(front) {
                GLMATERIALV(GL_FRONT, GL_AMBIENT, ambient);
                GLMATERIALV(GL_FRONT, GL_DIFFUSE, diffuse);
                GLMATERIALV(GL_FRONT, GL_SPECULAR, specular);
                GLMATERIAL(GL_FRONT, GL_SHININESS, shininess);
            }
            else if(back) {
                GLMATERIALV(GL_BACK, GL_AMBIENT, ambient);
                GLMATERIALV(GL_BACK, GL_DIFFUSE, diffuse);
                GLMATERIALV(GL_BACK, GL_SPECULAR, specular);
                GLMATERIAL(GL_BACK, GL_SHININESS, shininess);
            }
        }
        else
            glColor4d(diffuse[0],diffuse[1],diffuse[2],diffuse[3]);
    }

    //void set_no_diffuse()
    //{
    //    GLMATERIALV(GL_FRONT_AND_BACK, GL_DIFFUSE, ambient);
    //}


    private:
    void init(bool spec, bool amb)//, bool shine)
    {
        if(amb) {
            ambient[0] = 0.2;
            ambient[1] = 0.2; // default OpenGL ambient component
            ambient[2] = 0.2;
            ambient[3] = 1.0;
        }
        if(spec) {
            specular[0] = 0.0;  // dull
            specular[1] = 0.0;
            specular[2] = 0.0;  // default OpenGL specular component
            specular[3] = 1.0;
        }
        //if(shine)
            shininess = 128; // the lowest reflection
    }
};
#endif
